package com.yanqu.road.server.gameplayer.module.activity.yingxin;

import com.alibaba.fastjson.JSON;
import com.yanqu.road.entity.activity.ActivityInfo;
import com.yanqu.road.entity.activity.ppl.BallEliminate;
import com.yanqu.road.entity.activity.ppl.PplDrumReward;
import com.yanqu.road.entity.activity.ppl.PplShootResult;
import com.yanqu.road.entity.activity.ppl.shootlogic.PplScreenPos;
import com.yanqu.road.entity.activity.yingxin.YingXinUserData;
import com.yanqu.road.entity.activity.yingxin.config.HotPotCollectConfig;
import com.yanqu.road.entity.activity.yingxin.config.HotPotFloorConfig;
import com.yanqu.road.entity.activity.yingxin.config.YingXinConfig;
import com.yanqu.road.entity.activity.yingxin.config.YingXinMultiConfig;
import com.yanqu.road.entity.activity.yingxin.floor.YingXinFloorCellData;
import com.yanqu.road.entity.activity.yingxin.floor.YingXinFloorData;
import com.yanqu.road.entity.activity.yingxin.game.YingXinGameData;
import com.yanqu.road.entity.config.goods.GoodsInfo;
import com.yanqu.road.entity.config.goods.OpenGoodsBagResult;
import com.yanqu.road.entity.enums.eGamePlayerEventType;
import com.yanqu.road.entity.enums.eLogMoneyType;
import com.yanqu.road.entity.log.LogYingXinHotPot;
import com.yanqu.road.entity.log.LogYingXinShoot;
import com.yanqu.road.logic.bussiness.activity.YingXinBussiness;
import com.yanqu.road.logic.helper.CalcPowerResult;
import com.yanqu.road.logic.helper.PowerHelper;
import com.yanqu.road.pb.activity.YingXinProto;
import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.gameplayer.module.base.GeneralModule;
import com.yanqu.road.server.gameplayer.module.player.CurrencyModule;
import com.yanqu.road.server.manger.VipMgr;
import com.yanqu.road.server.manger.activity.ActivityMgr;
import com.yanqu.road.server.manger.activity.yingxin.YingXinEliminateLogic;
import com.yanqu.road.server.manger.activity.yingxin.YingXinGameLogic;
import com.yanqu.road.server.manger.activity.yingxin.YingXinMgr;
import com.yanqu.road.server.manger.activity.yingxin.YingXinShootLogic;
import com.yanqu.road.server.manger.config.GoodsBagMgr;
import com.yanqu.road.server.manger.config.GoodsMgr;
import com.yanqu.road.server.manger.log.AutoLogMgr;
import com.yanqu.road.server.manger.log.LogMgr;
import com.yanqu.road.server.pb.YingXinPb;
import com.yanqu.road.server.protocol.ClientProtocol;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.utils.RandomHelper;
import com.yanqu.road.utils.property.Property;
import com.yanqu.road.utils.property.PropertyHelper;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class YingXinModule extends GeneralModule {

    private RandomHelper randomHelper = new RandomHelper();

    private YingXinUserData userData;

    @Override
    public void afterLogin() {
        checkUserData();
        syncConfig();
        syncData();
    }

    /**
     * 同步配置
     */
    public void syncConfig() {
        YingXinConfig config = YingXinMgr.getConfig();
        if (config == null || !ActivityMgr.activityInShowTime(config.getActivityInfo())) {
            return;
        }

        YingXinProto.YingXinSyncConfigRespMsg.Builder builder = YingXinPb.parseYingXinSyncConfigRespMsg(config);
        player.sendPacket(ClientProtocol.U_ACTIVITY_YINGXIN_SYNC_CONFIG, builder);
    }

    /**
     * 同步数据
     */
    public void syncData() {
        YingXinConfig config = YingXinMgr.getConfig();
        if (config == null || !ActivityMgr.activityInShowTime(config.getActivityInfo())) {
            return;
        }

        if (userData != null) {
            YingXinProto.YingXinEnergyMsg.Builder builder = YingXinPb.parseYingXinEnergyMsg(userData);
            player.sendPacket(ClientProtocol.U_ACTIVITY_YINGXIN_SYNC_ENERGY, builder);
        }
    }

    /**
     * 初始化数据
     */
    public synchronized void initUserData() {

        YingXinConfig config = YingXinMgr.getConfig();

        if (config == null || !ActivityMgr.activityInShowTime(config.getActivityInfo())) {
            return; // 没活动
        }

        if (userData != null && userData.getActivityId() == config.getActivityInfo().getActivityId()) {
            return; // 已经有数据
        }

        YingXinUserData tmpData = new YingXinUserData();
        tmpData.setActivityId(config.getActivityInfo().getActivityId());
        tmpData.setUserId(player.getUserId());
        tmpData.setEnergy(config.getMaxEnergy());
        tmpData.setLastRecTime(System.currentTimeMillis());
        tmpData.setCollectList(new ConcurrentHashMap<>());
        for (Integer multi : config.getMultiMap().keySet()) {
            List<Integer> list = new ArrayList<>();
            for (int i = 0; i < config.getCollectList().size(); i++) {
                list.add(0);
            }
            tmpData.getCollectList().put(multi, list);
        }
        tmpData.setScore(0L);
        tmpData.setFloorDataMap(new ConcurrentHashMap<>());
        tmpData.setGotBigRewardMap(new ConcurrentHashMap<>());
        for (int type : config.getFloorMap().keySet()) {
            tmpData.getFloorDataMap().put(type, createYingXinFloorData(config, type, 1));
            tmpData.getGotBigRewardMap().put(type,0);
        }
        tmpData.setGameDataMap(new ConcurrentHashMap<>());
        for (Integer multi : config.getMultiMap().keySet()) {
            tmpData.getGameDataMap().put(multi, YingXinGameLogic.buildStartData(randomHelper));
        }
        tmpData.setInsertOption();

        userData = tmpData;
    }

    /**
     * 请求进来都检查下稳点
     */
    public void checkUserData() {
        if (!ActivityMgr.activityInShowTime(YingXinMgr.getActivityInfo())) {
            return;
        }
        if (userData == null) {
            initUserData();
        } else {
            int activityId = YingXinMgr.getActivityInfo().getActivityId();
            if (userData.getActivityId() != activityId) {
                initUserData();
            }
        }
        // 体力恢复
        calcEnergyRec();
    }

    /**
     * 生成一份火锅
     */
    private YingXinFloorData createYingXinFloorData(YingXinConfig config, int type, int floor) {
        Map<Integer, HotPotFloorConfig> configMap = config.getFloorMap().get(type);
        HotPotFloorConfig floorConfig = configMap.get(floor);

        List<YingXinFloorCellData> list = new ArrayList<>();

        // 随机其他八个奖励
        List<String> randomList = new ArrayList<>(floorConfig.getRewardList());
        randomHelper.shuffleList(randomList);
        for (String reward : randomList) {
            YingXinFloorCellData cell = new YingXinFloorCellData();
            cell.setOpen(false);
            cell.setSpec(false);
            cell.setReward(reward);
            list.add(cell); // 加到List
        }

        // 随机特殊奖励
        int specIndex = randomHelper.next(floorConfig.getRewardList().size() + 1);
        YingXinFloorCellData specCell = new YingXinFloorCellData();
        specCell.setOpen(false);
        specCell.setSpec(true);
        specCell.setReward(floorConfig.getSpecReward());
        list.add(specIndex, specCell); // 加到List

        // 设置奖励
        YingXinFloorData floorData = new YingXinFloorData();
        floorData.setFloor(floor);
        floorData.setCellList(list);
        return floorData;
    }

    /**
     * 计算体力恢复
     */
    private void calcEnergyRec() {
        YingXinConfig config = YingXinMgr.getConfig();
        if (config == null || userData == null) {
            return;
        }

        CalcPowerResult result = PowerHelper.calcPower(
                userData.getLastRecTime() / 1000,
                config.getRecoveryTime(),
                config.getRecoveryCount(),
                config.getMaxEnergy(),
                userData.getEnergy());

        userData.setEnergy(result.getCurPower());
        userData.setLastRecTime(result.getLastRecoverTime() * 1000);
    }

    /**
     * 使用体力药
     */
    public int useEnergyItem(int count) {

        if (count < 0 || count > 99999) {
            return GameErrorCode.E_ACTIVITY_YINGXIN_ITEM_NO_ENOUGH;
        }

        YingXinConfig config = YingXinMgr.getConfig();
        if (config == null || !ActivityMgr.activityInTime(config.getActivityInfo())) {
            return GameErrorCode.E_ACTIVITY_YINGXIN_NO_IN_TIME;
        }

        if (userData == null) {
            return GameErrorCode.E_ACTIVITY_YINGXIN_NO_UNLOCK;
        }

        // 消耗
        Property property = new Property();
        int energyItemId = config.getEnergyItemId();
        property.addProperty(energyItemId, BigInteger.valueOf(count));

        // 每个道具恢复体力数
        int recCount;
        GoodsInfo goodsInfo = GoodsMgr.getGoodsById(energyItemId);
        recCount = goodsInfo.getParamList().get(0).intValue();

        // 扣道具
        if (!player.getModule(CurrencyModule.class).removeCurrency(property, eLogMoneyType.YingXinActivity, eLogMoneyType.YingXinActivityUseEnergyItem)) {
            return GameErrorCode.E_ACTIVITY_YINGXIN_ITEM_NO_ENOUGH;
        }

        // 加体力
        userData.setEnergy(userData.getEnergy() + count * recCount);

        if (userData.getEnergy() >= config.getMaxEnergy()) {
            userData.setLastRecTime(System.currentTimeMillis());
        }

        // 返回
        YingXinProto.YingXinUseEnergyItemRespMsg.Builder builder = YingXinProto.YingXinUseEnergyItemRespMsg.newBuilder();
        builder.setRet(0);
        builder.setEnergyMsg(YingXinPb.parseYingXinEnergyMsg(userData));
        player.sendPacket(ClientProtocol.U_ACTIVITY_YINGXIN_USE_ENERGY_ITEM, builder);
        return 0;
    }

    /**
     * 获取游戏数据Msg
     */
    public int getGameDataMsg(int multi) {

        if (userData == null) {
            return GameErrorCode.E_ACTIVITY_YINGXIN_NO_UNLOCK;
        }

        YingXinConfig config = YingXinMgr.getConfig();
        if (config == null || !ActivityMgr.activityInShowTime(config.getActivityInfo())) {
            return GameErrorCode.E_ACTIVITY_YINGXIN_NO_IN_TIME;
        }

        // 检查多倍数据
        List<Integer> multiList;
        if (multi != 0) {
            multiList = new ArrayList<>(config.getMultiMap().keySet());
        } else {
            multiList = new ArrayList<>();
            multiList.add(multi);
        }

        // 获取数据
        List<YingXinProto.YingXinGameDataMsg> list = new ArrayList<>();
        for (int integer : multiList) {
            YingXinProto.YingXinGameDataMsg.Builder gameBuilder = YingXinPb.parseYingXinGameDataMsg(userData, integer);
            list.add(gameBuilder.build());
        }

        // 返回
        YingXinProto.YingXinGetGameDataRespMsg.Builder builder = YingXinProto.YingXinGetGameDataRespMsg.newBuilder();
        builder.setRet(0);
        builder.addAllGameData(list);
        player.sendPacket(ClientProtocol.U_ACTIVITY_YINGXIN_GET_GAME_DATA, builder);
        return 0;
    }

    /**
     * 获取火锅数据
     */
    public int getHotPotMsg(int type) {
        YingXinConfig config = YingXinMgr.getConfig();
        if (config == null || !ActivityMgr.activityInShowTime(config.getActivityInfo())) {
            return GameErrorCode.E_ACTIVITY_YINGXIN_NO_IN_TIME;
        }
        if (userData == null) {
            return GameErrorCode.E_ACTIVITY_YINGXIN_NO_UNLOCK;
        }
        YingXinFloorData floorData = userData.getFloorDataMap().get(type);
        if (floorData == null) {
            return GameErrorCode.E_ACTIVITY_YINGXIN_NO_UNLOCK;
        }
        int gotBigReward = 0;
        if (userData.getGotBigRewardMap().containsKey(type)){
            gotBigReward = userData.getGotBigRewardMap().get(type);
        }
        YingXinProto.YingXinHotPotDataMsg.Builder floorBuilder = YingXinPb.parseYingXinHotPotDataMsg(type, floorData,gotBigReward);

        YingXinProto.YingXinGetHotPotRespMsg.Builder builder = YingXinProto.YingXinGetHotPotRespMsg.newBuilder();
        builder.setRet(0);
        builder.setData(floorBuilder);
        player.sendPacket(ClientProtocol.U_ACTIVITY_YINGXIN_GET_HOT_POT, builder);
        return 0;
    }

    /**
     * 检查多倍场解锁
     */
    private boolean checkMultiUnlock(YingXinConfig config, int multi) {
        if (!config.getMultiMap().containsKey(multi)) {
            return false;
        }

        YingXinMultiConfig multiConfig = config.getMultiMap().get(multi);

        // 积分解锁
        if (multiConfig.getUnlockScore() >= 0 && userData.getScore() >= multiConfig.getUnlockScore()) {
            return true;
        }

        // VIP解锁
        if (multiConfig.getUnlockVipLv() >= 0) {
            int vipLv = VipMgr.getVipLv(player.getUserInfo().getVipExp());
            if (vipLv >= multiConfig.getUnlockVipLv()) {
                return true;
            }
        }

        return false;
    }

    /**
     * 挖火锅
     *
     * @param index 从0开始
     */
    public int digHotPot(int type, int floor, int index) {

        // 活动时间
        YingXinConfig config = YingXinMgr.getConfig();
        if (config == null || !ActivityMgr.activityInShowTime(config.getActivityInfo())) {
            return GameErrorCode.E_ACTIVITY_YINGXIN_NO_IN_TIME;
        }

        // 玩家数据
        if (userData == null) {
            return GameErrorCode.E_ACTIVITY_YINGXIN_NO_UNLOCK;
        }

        // 火锅配置
        if (!config.getFloorMap().containsKey(type) ||
                !config.getFloorMap().get(type).containsKey(floor) ||
                config.getFloorMap().get(type).get(floor).getRewardList().size() < index) {
            return GameErrorCode.E_ACTIVITY_YINGXIN_HOT_POT_PARAM_ERROR;
        }
        String consume = config.getFloorMap().get(type).get(floor).getConsume();
        Property consumeProp = PropertyHelper.parseStringToProperty(consume);

        // 获取数据
        YingXinFloorData floorData = userData.getFloorDataMap().get(type);
        if (floorData.getFloor() != floor) {
            return GameErrorCode.E_ACTIVITY_YINGXIN_HOT_POT_PARAM_ERROR;
        }
        YingXinFloorCellData cellData = floorData.getCellList().get(index);
        if (cellData.isOpen()) {
            return GameErrorCode.E_ACTIVITY_YINGXIN_HOT_POT_HAD_EAT;
        }
        Property rewardProp = PropertyHelper.parseStringToProperty(cellData.getReward());

        // 是否是顶楼
        boolean topFloor = !config.getFloorMap().get(type).containsKey(floor + 1);

        // 判断通关大奖
        Property passReward = null;
        if (cellData.isSpec() && topFloor) {
            int boxId = config.getPassBoxList().get(type - 1);
            if (boxId != 0) { // 0表示没配置这个奖励
                OpenGoodsBagResult openGoodsBagResult = GoodsBagMgr.getRandomGoods(boxId);
                passReward = openGoodsBagResult.getReward();
            }
        }

        // 吃火锅
        if (!player.getModule(CurrencyModule.class).removeCurrency(consumeProp, eLogMoneyType.YingXinActivity, eLogMoneyType.YingXinActivityEatHotPot)) {
            return GameErrorCode.E_ACTIVITY_YINGXIN_ITEM_NO_ENOUGH;
        }
        cellData.setOpen(true);
        // 加普通奖励
        player.getModule(CurrencyModule.class).addCurrency(rewardProp, eLogMoneyType.YingXinActivity, eLogMoneyType.YingXinActivityEatHotPot);
        // 加通关奖励
        if (passReward != null) {
            player.getModule(CurrencyModule.class).addCurrency(passReward, eLogMoneyType.YingXinActivity, eLogMoneyType.YingXinActivityPassHotPot);
        }

        // 判断楼层结束
        if (cellData.isSpec()) {
            YingXinFloorData newFloorData;
            if (topFloor) { // 回到第一层
                newFloorData = createYingXinFloorData(config, type, 1);
                userData.getGotBigRewardMap().put(type,1);
            } else { // 前往下一层
                newFloorData = createYingXinFloorData(config, type, floor + 1);
            }
            userData.getFloorDataMap().put(type, newFloorData);
        }

        // 改到Map了加个状态
        userData.setUpdateOption();

        // 返回
        YingXinProto.YingXinOpenHotPotRespMsg.Builder builder = YingXinProto.YingXinOpenHotPotRespMsg.newBuilder();
        builder.setRet(0);
        builder.setReward(cellData.getReward());
        builder.setSpec(cellData.isSpec());
        if (passReward != null) {
            builder.setPassReward(PropertyHelper.parsePropertyToString(passReward));
        }
        int gotBigReward = 0;
        if (userData.getGotBigRewardMap().containsKey(type)){
            gotBigReward = userData.getGotBigRewardMap().get(type);
        }
        builder.setData(YingXinPb.parseYingXinHotPotDataMsg(type, userData.getFloorDataMap().get(type),gotBigReward));
        player.sendPacket(ClientProtocol.U_ACTIVITY_YINGXIN_DIG_HOT_POT, builder);

        // 日志
//        LogMgr.addLogYingXinHotPot(new LogYingXinHotPot(
//                config.getActivityInfo().getActivityId(),
//                getUserId(),
//                type,
//                floor,
//                consume,
//                cellData.isSpec() ? 1 : 0,
//                cellData.getReward(),
//                passReward == null ? "" : PropertyHelper.parsePropertyToString(passReward)
//        ));

        AutoLogMgr.add(new LogYingXinHotPot(
                config.getActivityInfo().getActivityId(),
                getUserId(),
                type,
                floor,
                consume,
                cellData.isSpec() ? 1 : 0,
                cellData.getReward(),
                passReward == null ? "" : PropertyHelper.parsePropertyToString(passReward)
        ));

        return 0;
    }

    /**
     * 重新开始游戏
     */
    public int restartGame(int multi) {

        YingXinConfig config = YingXinMgr.getConfig();
        if (config == null || !ActivityMgr.activityInTime(config.getActivityInfo())) {
            return GameErrorCode.E_ACTIVITY_YINGXIN_NO_IN_TIME;
        }

        if (!checkMultiUnlock(config, multi)) {
            return GameErrorCode.E_ACTIVITY_YINGXIN_MULTI_NO_UNLOCK;
        }

        YingXinGameData gameData = userData.getGameDataMap().get(multi);
        if (!YingXinGameLogic.isGameOver(gameData)) {
            return GameErrorCode.E_ACTIVITY_YINGXIN_NO_GAMEOVER;
        }

        gameData.setHead(randomHelper.next(YingXinGameLogic.TOTAL_COLOR_COUNT) + 1);
        gameData.setCur(randomHelper.next(YingXinGameLogic.TOTAL_COLOR_COUNT) + 1);
        gameData.setMaxY(YingXinGameLogic.INIT_Y);
        gameData.setLines(new ArrayList<>());
        YingXinGameLogic.autoAddLine(config, gameData, randomHelper);
        return 0;
    }

    /**
     * 发射球
     */
    public int shootBall(int angle, int height, int multi) {

        YingXinConfig config = YingXinMgr.getConfig();
        if (config == null || !ActivityMgr.activityInTime(config.getActivityInfo())) {
            return GameErrorCode.E_ACTIVITY_YINGXIN_NO_IN_TIME;
        }

        if (userData == null) {
            return GameErrorCode.E_ACTIVITY_YINGXIN_NO_UNLOCK;
        }

        if (userData.getEnergy() < getMultiEnergyCostCount(multi)) {
            return GameErrorCode.E_ACTIVITY_YINGXIN_ENERGY_NO_ENOUGH;
        }

        if (!checkMultiUnlock(config, multi)) {
            return GameErrorCode.E_ACTIVITY_YINGXIN_MULTI_NO_UNLOCK;
        }

        YingXinGameData gameData = userData.getGameDataMap().get(multi);

        // 获取发射轨迹
        List<PplScreenPos> moveKeyPos = YingXinShootLogic.getMoveKeyPos(getUserId(), new BigDecimal(angle), gameData, new BigDecimal(height));

        // 特殊情况
        boolean outScreen = moveKeyPos.size() > 0 && moveKeyPos.get(moveKeyPos.size() - 1).getScreenY().compareTo(BigDecimal.ZERO) < 0;
        if (!outScreen && moveKeyPos.size() < 3) {
            log.error("activityId = {}!!! userId = {}!!! gameData = {}!!! angle = {}!!! height = {}!!! shoot error!",
                    config.getActivityInfo().getActivityId(), getUserId(), JSON.toJSONString(gameData), angle, height);
            return GameErrorCode.E_ACTIVITY_YINGXIN_POSITION_ERROR;
        }

        // 处理结果
        int ret;
        if (outScreen) {
            ret = shootBallOutScreen(config, multi, gameData, moveKeyPos);
        } else {
            ret = shootBallNormal(config, multi, gameData, moveKeyPos);
        }
        userData.setUpdateOption(); // 稳点
        return ret;
    }

    /**
     * 发射球飞出屏幕
     */
    private int shootBallOutScreen(YingXinConfig config, int multi, YingXinGameData gameData, List<PplScreenPos> moveKeyPos) {

        // 日志用
        int logBeforeEnergy = userData.getEnergy();

        // 扣体力
        int ret = removeEnergy(config, multi);
        if (ret != 0) {
            return ret;
        }

        // 变颜色
        gameData.setCur(randomHelper.next(YingXinGameLogic.TOTAL_COLOR_COUNT) + 1);

        // 返回
        YingXinProto.YingXinShootBallRespMsg.Builder builder = YingXinProto.YingXinShootBallRespMsg.newBuilder();
        builder.setRet(0);
        builder.addAllRouteList(YingXinPb.parseYingXinScreenPosMsgList(moveKeyPos));
        builder.setOutScreen(true);
        builder.setGameData(YingXinPb.parseYingXinGameDataMsg(userData, multi));
        player.sendPacket(ClientProtocol.U_ACTIVITY_YINGXIN_SHOOT_BALL, builder);

//        LogMgr.addLogYingXinShoot(new LogYingXinShoot(
//                config.getActivityInfo().getActivityId(),
//                getUserId(),
//                multi,
//                0,
//                gameData.getLines().size(),
//                logBeforeEnergy,
//                userData.getEnergy(),
//                0,
//                0,
//                ""
//        ));
        AutoLogMgr.add(new LogYingXinShoot(
                config.getActivityInfo().getActivityId(),
                getUserId(),
                multi,
                0,
                gameData.getLines().size(),
                logBeforeEnergy,
                userData.getEnergy(),
                0,
                0,
                ""
        ));

        return 0;
    }

    /**
     * 发射球正常处理
     */
    private int shootBallNormal(YingXinConfig config, int multi, YingXinGameData gameData, List<PplScreenPos> moveKeyPos) {
        // 停留点
        PplScreenPos stopPos = moveKeyPos.get(moveKeyPos.size() - 1);

        // 临时数据
        List<Integer> tmpCollectList = userData.getCollectList().get(multi);
        YingXinGameData tmpGameData = gameData.clone();

        // 消除
        PplShootResult result = YingXinEliminateLogic.eliminateBalls(config, randomHelper, tmpCollectList, tmpGameData, multi, stopPos.getX(), stopPos.getY());

        // 处理消除结果
        if (result.getRet() != 0) {
            return result.getRet();
        }

        // 日志用的
        int logBeforeEnergy = userData.getEnergy();
        long logOldScore = userData.getScore();

        // 扣体力
        int ret = removeEnergy(config, multi);
        if (ret != 0) {
            return ret;
        }

        // 设置值
        tmpGameData.setCur(randomHelper.next(YingXinGameLogic.TOTAL_COLOR_COUNT) + 1);
        userData.getCollectList().put(multi, tmpCollectList);
        userData.getGameDataMap().put(multi, tmpGameData);


        // 日志用
        LogYingXinDropBox logYingXinDropBox = new LogYingXinDropBox();

        // 加奖励
        getBoxRewards(config, result.getEliminateList(), multi, logYingXinDropBox); // 领取宝箱奖励
        result.setDrumRewardList(getHotPotFullReward(config, multi)); // 领取火锅收集奖励
        addEliminateScore(config, multi, result.getEliminateList()); // 领取积分奖励
        player.notifyListener(eGamePlayerEventType.YingXinScoreRank.getValue(), userData.getScore());
        player.notifyListener(eGamePlayerEventType.YingXinCrossScoreRank.getValue(), userData.getScore());

        // 返回
        YingXinProto.YingXinShootBallRespMsg.Builder builder = YingXinProto.YingXinShootBallRespMsg.newBuilder();
        builder.setRet(0);
        builder.setGameData(YingXinPb.parseYingXinGameDataMsg(userData, multi));
        builder.addAllBallList(YingXinPb.parseYingXinDropBallMsgList(result.getEliminateList()));
        builder.addAllHotPotList(YingXinPb.parseYingXinHotPotRewardMsgList(result.getDrumRewardList()));
        // 弹射点+被碰撞点+碰撞时自身的点+最终停留点
        moveKeyPos.remove(moveKeyPos.size() - 1);// 去掉停留点
        PplScreenPos collided = moveKeyPos.remove(moveKeyPos.size() - 2);// 去掉被碰撞点
        builder.addAllRouteList(YingXinPb.parseYingXinScreenPosMsgList(moveKeyPos));
        builder.setStopPoint(YingXinPb.parseYingXinArrayPosMsg(stopPos.getX(), stopPos.getY()));
        builder.setCollidedPoint(YingXinPb.parseYingXinArrayPosMsg(collided.getX(), collided.getY()));
        player.sendPacket(ClientProtocol.U_ACTIVITY_YINGXIN_SHOOT_BALL, builder);

        // 日志
//        LogMgr.addLogYingXinShoot(new LogYingXinShoot(
//                config.getActivityInfo().getActivityId(),
//                getUserId(),
//                multi,
//                result.getEliminateList().size(),
//                gameData.getLines().size(),
//                logBeforeEnergy,
//                userData.getEnergy(),
//                (int) (userData.getScore() - logOldScore),
//                logYingXinDropBox.getCount(),
//                logYingXinDropBox.getReward()
//        ));

        // 日志
        AutoLogMgr.add(new LogYingXinShoot(
                config.getActivityInfo().getActivityId(),
                getUserId(),
                multi,
                result.getEliminateList().size(),
                gameData.getLines().size(),
                logBeforeEnergy,
                userData.getEnergy(),
                (int) (userData.getScore() - logOldScore),
                logYingXinDropBox.getCount(),
                logYingXinDropBox.getReward()
        ));

        return 0;
    }

    /**
     * 扣体力
     */
    private int removeEnergy(YingXinConfig config, int multi) {

        // 判断够不够
        int removeCount = getMultiEnergyCostCount(multi);
        if (userData.getEnergy() < removeCount) {
            return GameErrorCode.E_ACTIVITY_YINGXIN_ENERGY_NO_ENOUGH;
        }

        boolean beforeMax = userData.getEnergy() >= config.getMaxEnergy();

        // 扣体力
        userData.setEnergy(userData.getEnergy() - removeCount);

        boolean afterMax = userData.getEnergy() >= config.getMaxEnergy();

        // 恢复时间
        if (beforeMax && !afterMax) {
            userData.setLastRecTime(System.currentTimeMillis());
        }
        return 0;
    }

    /**
     * 领取掉落的宝箱奖励
     */
    private void getBoxRewards(YingXinConfig config, List<BallEliminate> eliminateList, int multi, LogYingXinDropBox logYingXinDropBox) {
        Property property = new Property();
        for (BallEliminate ball : eliminateList) {
            if (ball.getColor() == -1) {

                // 日志
                logYingXinDropBox.setCount(logYingXinDropBox.getCount() + 1);

                int boxItemId = config.getBoxItemId();
                OpenGoodsBagResult randomGoods = GoodsBagMgr.getRandomGoods(boxItemId);
                Property tmpProp = randomGoods.getReward();

                // 多倍场奖励乘多倍
                tmpProp.rideProperty(getMultiBoxRewardParam(multi));

                ball.setReward(PropertyHelper.parsePropertyToString(tmpProp));
                property.addProperty(tmpProp);
            }
        }
        player.getModule(CurrencyModule.class).addCurrency(property, eLogMoneyType.YingXinActivity, eLogMoneyType.YingXinActivityDropBoxReward);

        // 日志
        if (logYingXinDropBox.getCount() > 0) {
            logYingXinDropBox.setReward(PropertyHelper.parsePropertyToString(property));
        }
    }

    /**
     * 领取火锅集满的奖励
     */
    public List<PplDrumReward> getHotPotFullReward(YingXinConfig config, int multi) {
        List<PplDrumReward> hotPotRewardList = new ArrayList<>();
        Property property = new Property();

        List<Integer> collectList = userData.getCollectList().get(multi);
        List<HotPotCollectConfig> configList = config.getCollectList();
        for (int i = 0; i < collectList.size() && i < configList.size(); i++) {
            Integer curCount = collectList.get(i);
            HotPotCollectConfig collectConfig = configList.get(i);
            int needBallCount = collectConfig.getNeedBallCount() * getMultiCollectNeedCountParam(multi);
            if (curCount >= needBallCount) {
                int times = curCount / needBallCount; // 兼容一次性领取一个鼓的多次集满奖励
                Property tmpProperty = PropertyHelper.parseStringToProperty(collectConfig.getFullReward());
                tmpProperty.rideProperty(times * getMultiCollectRewardParam(multi)); // 配置奖励 x 次数 x 倍数

                PplDrumReward drumReward = new PplDrumReward();
                drumReward.setIndex(i);
                drumReward.setReward(PropertyHelper.parsePropertyToString(tmpProperty));
                hotPotRewardList.add(drumReward);

                collectList.set(i, curCount - needBallCount * times);
                property.addProperty(tmpProperty);
            }
        }

        userData.setUpdateOption();
        player.getModule(CurrencyModule.class).addCurrency(property, eLogMoneyType.YingXinActivity, eLogMoneyType.YingXinActivityHotPotCollectReward);
        return hotPotRewardList;
    }

    /**
     * 添加消除球的积分
     */
    public synchronized void addEliminateScore(YingXinConfig config, int multi, List<BallEliminate> eliminateList) {
        List<HotPotCollectConfig> collectList = config.getCollectList();
        int totalScore = 0;
        for (BallEliminate ball : eliminateList) {
            if (ball.getColor() <= 0) {
                // 宝箱没积分
                continue;
            }
            HotPotCollectConfig collectConfig = collectList.get(ball.getDrumIndex());
            totalScore += collectConfig.getOneBallScore();
        }

        totalScore *= getMultiBallScoreParam(multi);

        userData.setScore(totalScore + userData.getScore());

        Property property = new Property();
        property.addProperty(config.getScoreItemId(), BigInteger.valueOf(totalScore));
        player.getModule(CurrencyModule.class).addCurrency(property, eLogMoneyType.YingXinActivity, eLogMoneyType.YingXinActivityDropBallAddScore);
    }

    public YingXinModule(GamePlayer player) {
        super(player);
    }

    @Override
    public boolean loadData() {
        ActivityInfo activityInfo = YingXinMgr.getActivityInfo();
        if (ActivityMgr.activityInShowTime(activityInfo)) {
            userData = YingXinBussiness.getYingXinUserData(activityInfo.getActivityId(), getUserId());
        }
        return true;
    }

    @Override
    public boolean afterLoadData() {
        checkUserData();
        return true;
    }

    @Override
    public boolean saveData() {
        if (userData != null) {
            if (userData.isInsertOption()) {
                YingXinBussiness.addYingXinUserData(userData);
            } else if (userData.isUpdateOption()) {
                YingXinBussiness.updateYingXinUserData(userData);
            }
        }
        return true;
    }

    // =============== 多倍 ================

    /**
     * 获取体力消耗
     */
    private int getMultiEnergyCostCount(int multi) {
        return multi;
    }

    /**
     * 获取宝箱奖励倍数
     */
    private int getMultiBoxRewardParam(int multi) {
        return multi;
    }

    /**
     * 获取球的积分倍数
     */
    private int getMultiBallScoreParam(int multi) {
        return multi;
    }

    /**
     * 获取多倍火锅收集总进度倍数
     */
    private int getMultiCollectNeedCountParam(int multi) {
        return multi;
    }

    /**
     * 获取多倍火锅收集奖励倍数
     */
    private int getMultiCollectRewardParam(int multi) {
        return multi;
    }

}
